; -------------------------------------------------------------
; Firmware for the CHILL OUT DoC DMX 8
; Powered by Vixen
; (c) 2011 Joshua Moyerman
;
; With input from Andrew Williams, Just Some Guy Productions
; Based On:
; JECPWM_3.asm
; (c) 2007 John Chapman, Engineering Solutions Inc
; Inspired somewhat by Microchip's application notes
; for receiving DMX and generating software PWM.
; Note: The reference designs for these pixels are distributed 
; under a Creative Commons license Attribution-ShareAlike 2.5
;
; 16F688 Chip Connections
;
; PORT		PIN		CONFIGURATION
; ==================================
; A0        13      Channel 2 & PGM Header 
; A1        12      Channel 3 & PGM Header
; A2        11      Channel 4
; C0        10      Channel 5
; C1        9       Channel 6
; C2        8       Channel 7
; C3        7       Channel 8
; C4        6       N/C
; C5        5       DMX512 RX
; A3        4       VPP
; A4        3       Channel 1
; A5        2       Channel 9
; GND       14      GND
; VCC       1		Vcc
;
; Revision History:
; 12/31/11	Initial
; 1/2/12	Expanded to 9 Channels and added WDT timer to fix hangups on
;		loss of DMX data for more than ~2 S
; 1/6/12	Started to add configurability in boards, and user options.
; 2/1/12	In-field programming works

; Future Hopes
;  Insert #ifdef for waitforchX
;  Port code to PIC16F1823-5
;  Board Support for wjohn's 3ch dmx dcssr
;  Sink Map similar to Renard Firmware?

; --------- Configurable Numbers  --------- 
#define DMX_START_ADDRESS D'1'	; Set the DMX value for the controller
#define DEFAULTVALUE 0x00	; Value that all LED's will turn on to when
							; controller starts

; Define number of channels used
#define		CHANNELS 9		; Valid options are 1 to 9 inclusive

; Define which processor you are using
#define		PROCESSOR 16F1825
; Current options are
; 16F688

; Define which board you are using
#define 	BOARD CHILLOUTDOCDOC
; Current options are :
#define		CHILLOUTDOCDOC 1
#define		WJOHN_3CH 2

#define		NOBOARD
; --------- Board Presets --------- 
#if BOARD == CHILLOUTDOCDOC

#define PROG_PORT       PORTA
#define PROG_PIN        3

#define CH1VAR		pinsa
#define CH1PORT		PORTA
#define CH1PIN		4

#define CH2VAR		pinsa
#define CH2PORT		PORTA
#define CH2PIN		0

#define CH3VAR		pinsa
#define CH3PORT		PORTA
#define CH3PIN		1

#define CH4VAR		pinsa
#define CH4PORT		PORTA
#define CH4PIN		2

#define CH5VAR		pinsc
#define CH5PORT		PORTC
#define CH5PIN		0

#define CH6VAR		pinsc
#define CH6PORT		PORTC
#define CH6PIN		1

#define CH7VAR		pinsc
#define CH7PORT		PORTC
#define CH7PIN		2

#define CH8VAR		pinsc
#define CH8PORT		PORTC
#define CH8PIN		3

#define CH9VAR		pinsa
#define CH9PORT		PORTA
#define CH9PIN		5

#define BOARD_TRUE
#endif	; BOARD == CHILLOUTDOCDOC

#if BOARD == WJOHN_3CH
	error Not Implemented Yet!
#define BOARD_TRUE
#endif	;BOARD == WJOHN_3CH

#ifndef BOARD_TRUE
	error Define a Board Please!
#endif

; --------- Don't Modify These Values --------- 
#define DMX_HIGH_BYTE   0x00	; Stores location of high byte in EEPROM
#define DMX_LOW_BYTE    0x01	; Stores location of low byte in EEPROM
#define DMX_STATUS_BYTE 0x02    ; See if has been field programmed before

;  --------- Check Defines ---------
; Check start channel
#define MAX_START_CHANNEL (512 - CHANNELS)

#if (DMX_START_ADDRESS > MAX_START_CHANNEL)
	error - - - - - - - - - - - - - - - - - - - -
	error * DMX START ADDRESS TOO HIGH! *
	error * Must be less than MAX_START_CHANNEL *              
	error - - - - - - - - - - - - - - - - - - - - 
#endif

#if (DMX_START_ADDRESS < 1)
	error - - - - - - - - - - - - - - -
	error * DMX START ADDRESS TOO LOW! *
	error * Must be one or higher *
	error - - - - - - - - - - - - - - -
#endif

; Check Number of Channels
#if (CHANNELS > 9)
	error - - - - - - - - - - - - - - - - - - - -
	error * Channels too high, max of 9 channels *
	error - - - - - - - - - - - - - - - - - - - - 
#endif

#if (CHANNELS < 1)
	error - - - - - - - - - - - - - - - - - - - 
	error * Channels too few, min of 1 channel *
	error - - - - - - - - - - - - - - - - - - - 
#endif
;  --------- End Defines and stuff you should modify ---------

;  --------- Includes and Configuration ---------
    ; Includes generated based on processor defined above.
    ; Will throw error if user selects an unsupported processor.

#if PROCESSOR == 16F688
	list      p=16F688      ; Usual list and include files (note caps)
	#include <P16F688.INC>
	__CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_OFF & _WDT_ON & _INTOSCIO
        ; OSC = INTOSCIO
	; Watchdog = Disabled
	; Power up Timer  = Disabled
	; MCLR = Reset
	; Brownout = Enabled, SBODEN disabled
	; Switchover = Disabled
	; Failsave = Disabled
	; Code = As needed
	; EEPROM = As needed
#define		BANK0	bcf	STATUS,RP0      ; These are used to switch
#define		BANK1	bsf	STATUS,RP0	; back and forth between banks

	errorlevel  -302		; Get rid of the bank sel warnings
#define PROCESSOR_GOOD
#endif  ; PROCESSOR == 16F688


#if PROCESSOR == 16F1825
        list    p=16F1825
        #include <P16F1825.INC>

#define         BANK0   movlb   b'00000'
#define         BANK1   movlb   b'00001'
#define         BANK2   movlb   b'00010'
#define         BANK3   movlb   b'00011'

        errorlevel  -302

#define PROCESSOR_GOOD
#endif  ; PROCESSOR == 1825

#ifndef PROCESSOR_GOOD
    error Unsupported Processor. Please see file for details
#endif

; --------- Variable Definitions --------- 
	CBLOCK 0x20
	wsave		; ISR Save
	ssave	
	psave

	pinsa		; Port Values
	pinsc
	
	IntCount	; Counter for PWM routine
        timer           ; Counter used for delay routines
        count           ; Another Counter for delay routines
	
	dmxhighbyte	; Start address
	dmxlowbyte
	
	skiphigh	; Counters used to wait for address	
	skiplow	
	
	temp		; Timer Var

        dmxstat         ; DMX Program routine vars
        dmxproghigh
        dmxproglow
        pskiphigh
        pskiplow
        newdmxhigh
        newdmxlow

	ENDC
	
; Auto-detect number of channels defined	
#if CHANNELS >= 1
	CBLOCK      0x3D
	ch1			
	ch1new
	ENDC
#endif
#if CHANNELS >= 2
	CBLOCK      0x2D
	ch2
	ch2new
	ENDC
#endif
#if CHANNELS >= 3
	CBLOCK      0X2F
	ch3
	ch3new
	ENDC
#endif
#if CHANNELS >= 4
	CBLOCK      0X31
	ch4
	ch4new
	ENDC
#endif
#if CHANNELS >= 5
	CBLOCK      0X33
	ch5
	ch5new
	ENDC
#endif
#if CHANNELS >= 6
	CBLOCK      0X35
	ch6
	ch6new
	ENDC
#endif
#if CHANNELS >= 7
	CBLOCK      0X37
	ch7
	ch7new
	ENDC
#endif
#if CHANNELS >= 8
	CBLOCK      0X39
	ch8
	ch8new
	ENDC
#endif
#if CHANNELS >= 9
	CBLOCK      0X3B
	ch9
	ch9new
	ENDC
#endif
; --------- End Var Defs ---------

; --------- Start Program ---------
	ORG 0x000			; Main Program

	clrf    PCLATH
	goto    start

	ORG     0x004			; Interrupt handler goes here

pwmdrive
 	movwf	wsave                   ; Store the usual bits when interrupting
 	swapf	STATUS, w
 	clrf	STATUS
 	movwf	ssave
 	movf	PCLATH, w
 	movwf	psave

; ------- Actual Interrupt Routine Here --------------------
; TMR0 will roll over every 40.0 uS which allows for 97.65 Hz PWM frequency
;  Nice thing here is that even if we're receiving  full-on DMX (44, 512-byte
;  frames per second) the PWM routine can easily keep up.  So some exciting
;  effects should be possible.
 	movlw 	D'190'		
 	movwf 	TMR0

DecIntCount						
	decfsz	IntCount,F	; Decrement IntCount register.  If 0, reset 
	goto	ch1check	; the PWM routine. Else check each PWM value

PWMReset			; We've been through 256 cycles of PWM, 
	clrf	PORTA		; time to clear the ports
	clrf	PORTC
	clrf	pinsa
	clrf	pinsc

	movlw	D'255'		; Reset the counter
	movwf	IntCount	; Also, since we're resetting, transfer
                                ; the *new variables to the working PWM vars
#if CHANNELS >= 1
        movf  	ch1new,w
        movwf 	ch1
#endif
#if CHANNELS >= 2
        movf  	ch2new,w
        movwf 	ch2
#endif
#if CHANNELS >= 3
        movf  	ch3new,w
        movwf	ch3
#endif
#if CHANNELS >= 4
	movf	ch4new,w
	movwf	ch4
#endif
#if CHANNELS >= 5
	movf	ch5new,w
	movwf	ch5
#endif
#if CHANNELS >= 6
	movf	ch6new,w
	movwf	ch6
#endif
#if CHANNELS >= 7
	movf	ch7new,w
	movwf	ch7
#endif
#if CHANNELS >= 8
	movf	ch8new,w
	movwf	ch8
#endif
#if CHANNELS >= 9
	movf	ch9new,w
	movwf	ch9
#endif

        goto	pwmexit		; Exit ISR

; Here we compare each of the duty cycles to the IntCount.  If the values
; match, the corresponding pin is driven high.  It's a bit counter-intuitive
; but it works.  Note that if a value of 255 is received, it won't work.  So 
; the DMX routine limits PWM values to [0 254].  Which is good enough.

; Note that the *val variables are used only within the PWM routine.  The actual
;  DMX data is stored in the *new variables, and transferred to these working
;  variables only when the PWM rolls over If the values are equal, set the bit
;  (which turns on the corresponding drive pin).

; We must store the values and then output them at the end due to a bad flicker
;  if we set the pin at each output.

; Autochecks the number of channels that needs to be output
#if CHANNELS >= 1
ch1check
	movf	ch1,w
	subwf	IntCount,w
	btfss	STATUS,Z	; Are they equal?
#if CHANNELS == 1
	goto	outputdata
#else
	goto	ch2check	
#endif
	bsf	CH1VAR,CH1PIN
#endif

#if CHANNELS >= 2
ch2check
	movf	ch2,w
	subwf	IntCount,w			         
	btfss	STATUS,Z
#if CHANNELS == 2     
	goto	outputdata
#else
	goto	ch3check
#endif
	bsf	CH2VAR,CH2PIN
#endif

#if CHANNELS >= 3
ch3check
	movf	ch3,w
	subwf	IntCount,w			         
	btfss	STATUS,Z  
#if CHANNELS == 3
	goto	outputdata
#else
	goto	ch4check
#endif
	bsf	CH3VAR,CH3PIN
#endif

#if CHANNELS >= 4
ch4check
	movf	ch4,w
	subwf	IntCount,w			         
	btfss	STATUS,Z  
#if CHANNELS == 4
	goto	outputdata
#else
	goto	ch5check
#endif	
	bsf	CH4VAR,CH4PIN
#endif

#if CHANNELS >= 5
ch5check
	movf	ch5,w
	subwf	IntCount,w
	btfss	STATUS,Z
#if CHANNELS == 5
	goto	outputdata
#else
	goto	ch6check
#endif
	bsf	CH5VAR, CH5PIN
#endif

#if CHANNELS >= 6
ch6check
	movf	ch6,w
	subwf	IntCount,w
	btfss	STATUS,Z
#if CHANNELS == 6
	goto	outputdata
#else
	goto	ch7check
#endif
	bsf     CH6VAR, CH6PIN
#endif

#if CHANNELS >= 7
ch7check
	movf	ch7,w
	subwf	IntCount,w
	btfss	STATUS,Z
#if CHANNELS == 7
	goto	outputdata
#else 
	goto	ch8check
#endif
	bsf     CH7VAR,CH7PIN
#endif

#if CHANNELS >= 8
ch8check
	movf	ch8,w
	subwf	IntCount,w
	btfss	STATUS,Z
#if CHANNELS == 8
	goto	outputdata
#else
	goto	ch9check
#endif
	bsf	CH8VAR,CH8PIN
#endif

#if CHANNELS >= 9
ch9check
	movf	ch9,w
	subwf	IntCount,w
	btfss	STATUS,Z
#if CHANNELS == 9
	goto	outputdata
#endif
	bsf	CH9VAR,CH9PIN
#endif

outputdata	
	movf	pinsa,w		; Move the values out to PORTA and PORTC
	movwf	PORTA		 
	movf	pinsc,w
	movwf	PORTC

pwmexit
 	bcf     INTCON,T0IF     ; Clear the TMR0 interrupt flag
 	movf	psave,w		; Restore whatever was happening prior
 	movwf	PCLATH		; to the interrupt and get back to
 	swapf	ssave,w		; gathering DMX data.
 	movwf	STATUS
 	swapf	wsave,f
 	swapf	wsave,w
 
 	retfie                  ; Back to gathering DMX data

; ---------- Main Program Starts Here ----------------------------
start
	call	chipinit	; Initialize pins, oscillator, etc
	call	meminit		; Clears Values (defaults controller to off)
	call	defaultdmxread  ; read coded value for start channel
	call 	dmxread		; read dmx number from EEPROM

	call	loop
	call 	loop			; extra startup time buffer
        ;btfss   PROG_PORT,PROG_PIN      ; Check for Program Jumper
        ;goto    dmxprogram              ; Go to program routine if jumper set
	call	pwminit			; Initialize TIMER0 and TMRO interrupts
	call 	rxinit			; Set up the EUSART to receive DMX

	BANK0

dmxcapture
	clrwdt			; Clear Watchdog Counter
	movf	dmxhighbyte,w	; Skipcounter is used to detmine how many
	movwf	skiphigh	; received data bytes are skipped before the RGB
	movf	dmxlowbyte,w	; data is collected.  Load skipcounter with
	movwf	skiplow		; the DMX address from above...

	movf  	skiplow,f	; ... then decrement it by one so we
  	btfsc	STATUS,Z	; know how many channels to ignore before the
   	decf  	skiphigh,f	; useful data arrives.  We'll see more of the 
  	decf  	skiplow,f	; skipcounter a bit farther down the page.

waitbreak
	clrwdt			; Clearing the wdt here removes the need for a 
                                ; keep-alive signal

	btfsc	PIR1,RCIF	; Here we're waiting to see if a break occurs
	movf	RCREG,w		; in the data signal.  Since we're *only*
	btfss	RCSTA,FERR	; receiving DMX, anything which generates a 
	goto	waitbreak	; framing error in the EUSART will count as a
	movf	RCREG,w		; break. If a byte is received correctly, dump
				; it and loop back until we get the error we 
				; need without being able to synchronzie to the
				; break signal there's no way to extract valid
                                ; DMX data
waitforstart
	btfss	PIR1,RCIF	; Now that a break signal is detected, 
	goto 	waitforstart	; loop until a new byte is received *without*
	btfsc	RCSTA,FERR	; a framing error.  If all is well AND the
	goto 	waitforstart	; new byte is zero (which means the start code
	movf	RCREG,w		; is also zero, it's okay to begin gethering
				; channel data

	; RIGHT NOW WE'RE NOT TESTING FOR A ZERO START CODE. 
        ; THIS WILL BE CHANGED IN FUTURE VERSIONS OF THE CODE.  BUYER BEWARE!

	movf	dmxhighbyte,1	; Here check to see if the highbyte is
	btfss	STATUS,Z	; zero. If it is,check to see if the	
	goto 	bytecapture	; lowbyte is 1.  If 1, grab the next three bytes
	movf	dmxlowbyte,w	; which come through. If !=1, go to the routine
	xorlw	D'1'		; which receives and discards bytes until the 
	btfsc	STATUS,Z	; DMX address has been reached.
	goto 	waitforch1		

bytecapture	

	btfss	PIR1,RCIF	; If we're here, it's because the start address
	goto  	bytecapture	; is greater than one. Hover until a byte is
	movf	RCREG,w		; received. Then, capture & move to 'w'...
							
 	movf  	skiplow,f	; ...decrement the skip counter... 
  	btfsc	STATUS,Z	; (all sixteen bits of it)
   	decf  	skiphigh,f
  	decf  	skiplow,f
				; ...and see if we've reached the start address.
	movf	skiplow,1	; If the skip counter now equals zero, we know
	btfss	STATUS,Z	; that we need to gather the next three bytes	
	goto 	bytecapture	; and save them as RGB data.  If the counter is
	movf	skiphigh,1	; still nonzero, loop back and do it again.
	btfss	STATUS,Z
	goto	bytecapture

waitforch1
	btfss	PIR1,RCIF	; Wait until CH1 byte is received
	goto 	waitforch1	; once it arrives, store it in 'temp'
	movf	RCREG,w		; and call the 'maxcheck'  routine.  Since the	
	movwf	temp		; PWM code only works for values between [0 254]
	call	maxcheck	; maxcheck will set levels of 0xFF to 0xFE
	movwf	ch1new		; then store them in the proper bit bucket.
				; remember the the *new variables are converted
				; to *val variables when the PWM routine resets
				; itself
waitforch2	
	btfss	PIR1,RCIF	; process is repeated for CH2 data
	goto 	waitforch2
	movf	RCREG,w
	movwf	temp
	call	maxcheck
	movwf	ch2new

waitforch3			; ...and for CH3 data
	btfss	PIR1,RCIF
	goto 	waitforch3
	movf	RCREG,w
	movwf	temp
	call	maxcheck
	movwf 	ch3new

waitforch4                      ; ... and for CH4 etc.
	btfss	PIR1,RCIF
	goto 	waitforch4
	movf	RCREG,w
	movwf	temp
	call	maxcheck
	movwf	ch4new
waitforch5
	btfss	PIR1,RCIF
	goto 	waitforch5
	movf	RCREG,w
	movwf	temp
	call	maxcheck
	movwf	ch5new
waitforch6	
	btfss	PIR1,RCIF
	goto 	waitforch6
	movf	RCREG,w
	movwf	temp
	call	maxcheck
	movwf	ch6new
waitforch7
	btfss	PIR1,RCIF
	goto 	waitforch7
	movf	RCREG,w
	movwf	temp
	call	maxcheck
	movwf	ch7new
waitforch8
	btfss	PIR1,RCIF
	goto 	waitforch8
	movf	RCREG,w
	movwf	temp
	call	maxcheck
	movwf	ch8new
waitforch9
	btfss	PIR1,RCIF
	goto 	waitforch9
	movf	RCREG,w
	movwf	temp
	call	maxcheck
	movwf	ch9new

	goto 	dmxcapture	; Got all bytes? Repeat
                                ; We're not checking to see if the DMX packet
                                ; Has run out in the meantime. However, anything
                                ; crazy should be caught by the WDT

 
; ----------- Routines for Starting the Chip ---------
chipinit
#if PROCESSOR == 16F688
	BANK0                   ; Memory bank 0
	movlw	b'00010111'	; Set WDT Prescaler
	movwf	WDTCON

	clrf	PORTC		; All PORTC Pins off
	clrf	PORTA		; All PORTA off
	clrf	CMCON0		; Comparators aren't used either
	clrf	CMCON1

	BANK1			; Set pins as outputs
#if CHANNELS >= 1
        bcf     CH1PORT,CH1PIN
#endif
#if CHANNELS >= 2
        bcf     CH2PORT,CH2PIN
#endif
#if CHANNELS >= 3
        bcf     CH3PORT,CH3PIN
#endif
#if CHANNELS >= 4
        bcf     CH4PORT,CH4PIN
#endif
#if CHANNELS >= 5
        bcf     CH5PORT,CH5PIN
#endif
#if CHANNELS >= 6
        bcf     CH6PORT,CH6PIN
#endif
#if CHANNELS >= 7
        bcf     CH7PORT,CH7PIN
#endif
#if CHANNELS >= 8
        bcf     CH8PORT,CH8PIN
#endif
#if CHANNELS >= 9
        bcf     CH9PORT,CH9PIN
#endif
	
	clrf	ANSEL           ; Turn off A/D Converters
	bsf	OSCCON,6	; Set these three
	bsf	OSCCON,5	; bits to enable the
	bsf	OSCCON,4	; 8 MHz internal oscillator
#endif

#if PROCESSOR == 16F1825
        BANK1
        movlw   b'00000000'     ; Set up internal clock
                ; 0xxxxxxx      4x PLL disabled
                ; x1110xxx      8 MHZ Frequency
                ; xxxxx0xx      Unimplemented
                ; xxxxxx10      Use Internal Clock
        movwf   OSCCON

#if CHANNELS >= 1
        bcf     CH1PORT,CH1PIN
#endif
#if CHANNELS >= 2
        bcf     CH2PORT,CH2PIN
#endif
#if CHANNELS >= 3
        bcf     CH3PORT,CH3PIN
#endif
#if CHANNELS >= 4
        bcf     CH4PORT,CH4PIN
#endif
#if CHANNELS >= 5
        bcf     CH5PORT,CH5PIN
#endif
#if CHANNELS >= 6
        bcf     CH6PORT,CH6PIN
#endif
#if CHANNELS >= 7
        bcf     CH7PORT,CH7PIN
#endif
#if CHANNELS >= 8
        bcf     CH8PORT,CH8PIN
#endif
#if CHANNELS >= 9
        bcf     CH9PORT,CH9PIN
#endif

        BANK0
        movlw   b'00010111'     ; Set WDT Scaler 1:65536
        movwf   WDTCON

	clrf	PORTC		; All PORTC Pins off
	clrf	PORTA		; All PORTA off

        clrf    CM1CON0
        clrf    CM1CON1
        clrf    CM2CON0
        clrf    CM2CON1

        BANK3                   ; Turn off analog input functions
        clrf    ANSELA
        clrf    ANSELC
#endif

	return

; ------------ Memory Init (Run at Startup) ------------ 
; Fills memory with default PWM Values
; Processor Independent code
meminit
	BANK0
	movlw	DEFAULTVALUE

#if CHANNELS >= 1
	movwf	ch1
	movwf	ch1new
#endif
#if CHANNELS >= 2
	movwf	ch2
	movwf	ch2new
#endif
#if CHANNELS >= 3
	movwf	ch3
	movwf	ch3new
#endif
#if CHANNELS >= 4
	movwf	ch4
	movwf	ch4new
#endif
#if CHANNELS >= 5
	movwf	ch5
	movwf	ch5new
#endif
#if CHANNELS >= 6
	movwf	ch6
	movwf	ch6new
#endif
#if CHANNELS >= 7
	movwf	ch7
	movwf	ch7new
#endif
#if CHANNELS >= 8
	movwf	ch8
	movwf	ch8new	
#endif
#if CHANNELS >= 9
	movwf	ch9
	movwf	ch9new
#endif
	return

rxinit
#if PROCESSOR == 16F688
	BANK0
	bsf	TRISC,5		; PORTC.5 is input for DMX data to EUSART
	clrf	TXSTA		; Clear TXSTA register
	movlw 	B'10010000'	; Serial Port and continuous receive enabled
	movwf	RCSTA				
	movlw	D'1'		; for baud rate generator
	movwf	SPBRG		
	clrf	SPBRGH		; This combination assures 0% error when
	bsf	BAUDCTL,BRG16   ; receiving DMX at 250,000 bits per second
	return			; the PLL makes it possible to grab such
				; high speed data without any error
#endif
#if PROCESSOR == 16f1825
        BANK0
        bsf     TRISC,5         ; PORTC 5 input for DMX (necessary?)
        clrf    TXSTA
        movlw   b'10010000'     ; Setup for DMX recieve

#endif

pwminit
; Compatible with 16F688 and 16F1825
	movlw	B'10100000'	; Enable global and TMR0 interrupts
	movwf	INTCON
	BANK1
	clrf	OPTION_REG	; No prescaler for TMR0 needed
	BANK0	
	return
; ----------------- Other Subroutines Go Here

maxcheck

	; Processes value which is stored in W. 
	; New value is also in W when routine exits

	xorlw	D'255'		; Here we're checking to see if a received
	btfsc	STATUS,Z	; byte is greater than 254.  If it is,
	goto 	exit		; set it to 254.  If it's less than 254
	movf	temp,w		; leave it alone and the PWM routine will
	return			; deal with it shortly
exit
	movlw	D'254'
	return

; ----------------- dmxread -------
dmxread 
; read the dmx address from the eeprom
; Check to see if the address has ever been set.
        BANK1
        movlw   DMX_STATUS_BYTE     ; eeprom addr to read from
        movwf   EEADR               ; data address to read from
        bcf     EECON1, EEPGD       ; point to adata memory
        bsf     EECON1, RD          ; EE Read
        movf    EEDAT, w            ; Copy read value
	BANK0
        movwf   dmxstat         ; to status
        btfsc   dmxstat,0       ; is the bit clear?
        return                  ; We've never recieved a channel from
                                ; field programming, so lets not read
                                ; the EE since it has nothing useful.

	; Second read the dmxhighbyte
	BANK1
	movlw	0x00 		; eeprom addr
	movwf 	EEADR		; data address to read
	bcf	EECON1, EEPGD 	; point to adata memory
	bsf	EECON1, RD	; EE read
	movf	EEDAT, w	; w = eeprom data.
	BANK0
	movwf	dmxhighbyte	; now in dmxhighbyte mem location

	; now read the dmxlowbyte
	BANK1
	movlw 	0x01		; eeprom addr
	movwf 	EEADR		; data address to read
	bcf	EECON1, EEPGD 	; point to adata memory
	bsf	EECON1, RD	; EE read
	movf	EEDAT, w	; w = eeprom data.
	BANK0
	movwf	dmxlowbyte	; now in dmxlowbyte

	return

; defaultdmxread is called first, it reads the value hard coded in the assembly
; If there is a value in the eeprom, this will be overwritten.
defaultdmxread
; Processor independent
	movlw	high DMX_START_ADDRESS	; Don't set the DMX Address here. 
	movwf	dmxhighbyte
	movlw	low DMX_START_ADDRESS
	movwf	dmxlowbyte		
        return


; ----------------- dmxprogram -------
dmxprogram
	call rxinit
	bsf	CH1PORT,CH1PIN
                                
        movlw   D'0'            
        movwf   dmxproghigh     
        movlw   D'1'            
        movwf   dmxproglow      
                                
        BANK0

dmxprogcapture
        movf    dmxproghigh,w   
        movwf   pskiphigh       
        movf    dmxproglow,w    
        movwf   pskiplow        

        movf    pskiplow,f      
        btfsc   STATUS,Z        
        decf    pskiphigh,f     
        decf    pskiplow,f      

progbreak
        btfsc   PIR1,RCIF       
        movf    RCREG,w         
        btfss   RCSTA,FERR      
        goto    progbreak       
        movf    RCREG,w         
                                
                                
                                
progstart
        btfss   PIR1,RCIF       
        goto    progstart	
        btfsc   RCSTA,FERR      
        goto    progstart	
        movf    RCREG,w         

        ; RIGHT NOW WE'RE NOT TESTING FOR A ZERO START CODE.
        ; THIS WILL BE CHANGED IN FUTURE
        ; VERSIONS OF THE CODE.  BUYER BEWARE!

        movf    dmxproghigh,1           
        btfss   STATUS,Z                
        goto    progcapture             
        movf    dmxproglow,w            
        xorlw   D'1'                    
        btfsc   STATUS,Z                
        goto    waitforhigh

progcapture
        btfss   PIR1,RCIF               
        goto    progcapture             
        movf    RCREG,w                 
        movf    pskiplow,f              
        btfsc   STATUS,Z                
        decf    pskiphigh,f
        decf    pskiplow,f
                                        
        movf    pskiplow,1              
        btfss   STATUS,Z                
        goto    progcapture             
        movf    pskiphigh,1             
        btfss   STATUS,Z
        goto    progcapture

waitforhigh
        btfss   PIR1,RCIF               
        goto    waitforhigh             
        movf    RCREG,w
        movwf   newdmxhigh

waitforlow
        btfss   PIR1,RCIF
        goto    waitforlow
        movf    RCREG,w
        movwf   newdmxlow
	bsf 	CH6PORT,CH6PIN

; Program the high byte

; clear the EEIF interupt bit
	bcf	PIR1,EEIF

	BANK1
	movlw 	DMX_HIGH_BYTE           ;DMX HIGH ADDRESS
	movwf 	EEADR 			;Data Memory Address to write
	BANK0
	movf	newdmxhigh,w 				;
	BANK1
	movwf	EEDAT 			;Data Memory Value to write
	bcf	EECON1, EEPGD 		;Point to DATA memory
	bsf	EECON1, WREN 		;Enable writes
	bcf	INTCON, GIE 		;Disable INTs.
	btfsc	INTCON, GIE 		;SEE AN576
	goto	$-2
	movlw	0x55 ;
	movwf	EECON2 			;Write 55h
	movlw	0xAA 			;
	movwf	EECON2 			;Write AAh
	bsf	EECON1, WR 		;Set WR bit to begin write

; need to keep checking for EEIF being set (write complete.)
	BANK0
ee_wri	
	btfss	PIR1,EEIF
	goto	ee_wri
	bcf	PIR1,EEIF		; clear the EEIF write complete interupt
	BANK1
	bcf	EECON1, WREN 		;Disable writes

; Program the low byte
	movlw 	DMX_LOW_BYTE			;DMX LOW ADDRESS
	movwf 	EEADR 			;Data Memory Address to write
	BANK0
	movf	newdmxlow,w
	BANK1
	movwf	EEDAT 			;Data Memory Value to write
	bcf	EECON1, EEPGD 		;Point to DATA memory
	bsf	EECON1, WREN 		;Enable writes
	bcf	INTCON, GIE 		;Disable INTs.
	btfsc	INTCON, GIE 		;SEE AN576
	goto	$-2
	movlw	0x55 			;
	movwf	EECON2 			;Write 55h
	movlw	0xAA 			;
	movwf	EECON2 			;Write AAh
	bsf	EECON1, WR 		;Set WR bit to begin write
; need to keep checking for EEIE being set (write complete.)
	BANK0
ee_wri1
	btfss	PIR1,EEIF
	goto	ee_wri1
	bcf	EECON1, WREN 		;Disable writes
	BANK1
	bcf	PIR1,EEIF		; clear the EEIF write complete interupt

; Program the DMX_STATUS_BYTE as 00
	movlw 	DMX_STATUS_BYTE			;
	movwf 	EEADR 			;Data Memory Address to write
	BANK0
	
	BANK1
	clrf	EEDAT
	bcf	EECON1, EEPGD 		;Point to DATA memory
	bsf	EECON1, WREN 		;Enable writes
	bcf	INTCON, GIE 		;Disable INTs.
	btfsc	INTCON, GIE 		;SEE AN576
	goto	$-2
	movlw	0x55 			;
	movwf	EECON2 			;Write 55h
	movlw	0xAA 			;
	movwf	EECON2 			;Write AAh
	bsf	EECON1, WR 		;Set WR bit to begin write
; need to keep checking for EEIE being set (write complete.)
	BANK0
ee_wri2	
	btfss	PIR1,EEIF
	goto	ee_wri2
	bcf	EECON1, WREN 		;Disable writes
	BANK1
	bcf	PIR1,EEIF		; clear the EEIF write complete interupt

	BANK0

; Finished programming, flash green infinitely (ch3 of RGB = G, green means go)
progend
	bsf 	CH2PORT,CH2PIN			; Turn on Green
	call 	loop1sec
	bcf 	CH2PORT,CH2PIN			; Turn off Green
	call 	loop1sec
	goto	progend

; --------- END PROGRAM ROUTINE ---------

; --------- Delay Routines ---------
loop
    movlw   d'250'          ; 250mS
    call    WaitNms
    return

loop1sec
    call loop
    call loop
    call loop
    call loop
    return

WaitNms
    movwf   timer           ; timer = w
loopNms
    movlw   d'248'          ; 250-2 instructions
    call    Wait1Ms
    ;goto    $-1
    decfsz  timer,f
    goto loopNms
    return

Wait1Ms
    movlw   d'255'          ;initial value, check..?
    movwf   count
loop1ms
    decfsz  count,1
    goto    loop1ms
    return
	END